/**
 * @Author: 陈瑞鹏
 * @Date:   2021-11-08 19:19:24
 * @Last Modified by:   陈瑞鹏
 * @Last Modified time: 2023-01-11 09:46:53
 */

import BaseGameLayer, { LAYER_Z_INDEX } from "../core/BaseGameLayer";
import { Dictionary } from "../core/Dictionary";
import { GameFacade } from "../core/GameFacade";
import { PureMVCEvents } from "../core/PureMVCEvents";
import { TouchRemove } from "../core/TouchRemove";
import { ResManager } from "./ResManager";

class PrivateClassForSceneManager { };

export class SceneManager {

  private _pushLayerParentDict: { [key: number]: cc.Node; } = null;

  private _layerPrefabsPath: string = 'prefabs/layers/';

  private _pushLayerDict: Array<BaseGameLayer> = null;

  private _preloadLayer: Dictionary<string, boolean> = new Dictionary<string, boolean>();

  private static _instance: SceneManager = null;

  private _swallowLayer: cc.Button = null;

  public constructor(sign: PrivateClassForSceneManager) {
    this._pushLayerDict = new Array<BaseGameLayer>();

    this._pushLayerParentDict = {};
  }


  public static getInstance(): SceneManager {

    if (!SceneManager._instance) {

      SceneManager._instance = new SceneManager(PrivateClassForSceneManager);

      SceneManager._instance._swallowLayer = new cc.Node().addComponent(cc.Button);
      SceneManager._instance._swallowLayer.node.addComponent(cc.Sprite);
      SceneManager._instance._swallowLayer.node.addComponent(TouchRemove);

      cc.resources.load('ui/bg_view_back', cc.SpriteFrame, function (err, sp: cc.SpriteFrame) {
        SceneManager._instance._swallowLayer.node.getComponent(cc.Sprite).spriteFrame = sp;
      });

    }

    return SceneManager._instance;
  }

  /**
   * 加载场景
   * @param sceneName 场景名
   * @param clearPushLayer  是否清空Layer 
   * @param finishedLoadedCallbakcFunc  加载完成回调
   */
  public loadScene(sceneName: string, clearPushLayer: boolean = false, finishedLoadedCallbakcFunc: Function = null): void {
    //先清空当前场景资源
    //let sceneRootNode = this.getCurrScene();
    //Utils.destroyRes( sceneRootNode.dependAssets );
    this.removeAllLayer(clearPushLayer);

    this.preLoadScene(sceneName, function (error: Error) {
      cc.director.loadScene(sceneName, finishedLoadedCallbakcFunc);
    });
  }

  /**
   * 加载 弹出层
   * @param layerName 
   * @param userData 
   * @param callbackFunc 
   */
  public pushLayer(layerName: string, userData: any = null, callbackFunc: Function = null): void {

    // if (this._swallowLayer && this._swallowLayer.node && this._swallowLayer.node.parent != this.getCurrScene()) {
    //   this._swallowLayer.node.parent = null;
    //   SceneManager.getInstance().getCurrScene().addChild(SceneManager._instance._swallowLayer.node, 999);
    //   this._swallowLayer.node.height = cc.winSize.height;
    //   this._swallowLayer.node.width = cc.winSize.width;
    //   this._swallowLayer.node.x = cc.winSize.width / 2;
    //   this._swallowLayer.node.y = cc.winSize.height / 2;
    //   this._swallowLayer.node.opacity = 15;
    // }

    let layer = this.getLayer(layerName);
    let index: LAYER_Z_INDEX = !layer ? LAYER_Z_INDEX.DEFAULT : layer.getLayerLocalIndex();
    // console.log("11")
    if (!this._pushLayerParentDict[index]) {
      // console.log("211")
      this._pushLayerParentDict[index] = new cc.Node();
      this.getCurrScene().addChild(this._pushLayerParentDict[index], index);
      this._pushLayerParentDict[index].width = cc.winSize.width;
      this._pushLayerParentDict[index].height = cc.winSize.height;
      this._pushLayerParentDict[index].x = cc.winSize.width / 2;
      this._pushLayerParentDict[index].y = cc.winSize.height / 2;
    } else if (!this._pushLayerParentDict[index].parent) {
      // console.log("113")
      // console.log(this._pushLayerParentDict, index, this.getCurrScene())
      this.getCurrScene().addChild(this._pushLayerParentDict[index], index);
      // console.log("114")
    }

    if (this._pushLayerParentDict[index].zIndex != index) {
      this._pushLayerParentDict[index].zIndex == index
    }

    if (!layer && !this._preloadLayer.get(layerName)) {
      if ((!userData || !userData.withoutUiLoadingLayer) && layerName != 'UILoadingLayer' && layerName != "ConnectNetLayer" && layerName != "NetAnnounceLayer") {
        //cc.log( "加载UILoadingLayer" );
        this.pushLayer('UILoadingLayer');
      }
      cc.log("预加载" + layerName);
      this.preloadLayer(layerName, userData, callbackFunc);
    } else if (layer) {
      if (layerName != 'UILoadingLayer') {
        //  如果UILoadingLayer预加载好发生在这之后，那么这个界面就无法删除
        //因此UILoadingLayer必须被预加载
        //cc.log( "删除UILoadingLayer" );
        this.removeLayer('UILoadingLayer', null);
      }

      if (layer.getDisplayView().parent) {
        layer.getDisplayView().parent.removeChild(layer.getDisplayView());
      }
      layer.setPushLayerCustomData(userData);

      let node = this._pushLayerParentDict[index];
      let zIndex: number = node.childrenCount;
      node.addChild(layer.getDisplayView(), zIndex + 1);

      this.actionPushLayer(layer.getDisplayView(), layer);
      if (callbackFunc) callbackFunc();
      layer.setIsRunning(true);

      if (layer.isRemoveSameLayer) {
        let nodeList: Array<cc.Node> = node.children;
        console.log(nodeList)
        for (let k = 0; k < nodeList.length; ++k) {
          if (nodeList[k] != layer.node) {
            nodeList[k].removeFromParent(false);
          }
        }
      }
    }
  }

  /**
   * 预加载 弹出层
   * @param layerName 
   * @param userData 
   * @param callbackFunc 
   * @param isPush 
   */
  public preloadLayer(layerName: string, userData: any = null, callbackFunc: Function = null, isPush: boolean = true): void {

    let self: SceneManager = this;
    let resPath = this._layerPrefabsPath + layerName;
    let loadCallbackFunc = function (err, layerPrefab) {

      if (!layerPrefab || err) {
        self.removeLayer('UILoadingLayer', null);
        // self.pushLayer('NetAnnounceLayer');
        return;
      }
      let layerNode = cc.instantiate(layerPrefab);
      let layer = layerNode.getComponent(layerName);
      self._pushLayerDict.push(layer);
      layer.setPrefab(layerPrefab);

      if (isPush) {
        cc.log("界面预加载完毕:" + layerName);
        self.pushLayer(layerName, userData);
      }

      if (callbackFunc) callbackFunc();

      self._preloadLayer.set(layerName, true);
    };

    let loadProFunc = function (completedCount, totalCount, item) {

      GameFacade.getInstance().sendNotification(PureMVCEvents.ON_UI_LOAD_UPDATE, { completedCount, totalCount })
    }

    if (!this._preloadLayer.get(layerName)) {

      ResManager.getInstance().loadRes(resPath, cc.Prefab, loadProFunc, loadCallbackFunc);
      cc.log('preload layer: ' + layerName);
    } else {
      //cc.log'preload layer is exist: '+ layerName);
    }
  }

  /**
   * 删除 弹出层
   * @param layerName 
   * @param callbackFunc 
   */
  public removeLayer(layerName: string, callbackFunc: Function = null): void {
    let layer = this.getLayer(layerName);
    let that: SceneManager = this;

    if (layer && layer.getIsRunning()) {
      layer.setPushLayerCustomData(null);
      this.actionRemoveLayer(layer, function () {
        layer.setIsRunning(false);

        layer.onRemoveFromStage();

        if (layer && layer.isReleaseResOnRemoveLayer) {
          that.releaseLayer(layer);
        }
      });
    } else if (!layer) {
      //cc.log(layerName + ' is not exist !');
    } else if (!layer.getIsRunning()) {
      //cc.log( 'Warning : User remove zIndex ' + layerName + ' , but it is not running !');
    }

    if (callbackFunc) {
      callbackFunc();
    }
  }

  /**
   * 
   */
  public removeTopLayer(): void {
    for (let k = LAYER_Z_INDEX.PUSH_LAYER_INDEX_4; k >= LAYER_Z_INDEX.PUSH_LAYER_INDEX_1; --k) {
      let layer: cc.Node = this.getTopLayer(k);
      if (layer && layer.active) {
        this.removeLayer(layer.name);
        break;
      }
    }
  }

  /**
   * 
   * @param index 
   */
  public getTopLayer(index: LAYER_Z_INDEX): cc.Node {
    let layer: cc.Node = null;

    let parent: cc.Node = this._pushLayerParentDict[index];

    if (!parent || (parent.children && !parent.children.length)) return layer;

    let count: number = parent.childrenCount;
    if (count) {
      layer = parent.children[count - 1];
    }
    return layer;
  }

  /**
   * 根据 zindex获取 父节点
   * @param index 
   */
  public getPushLayerParent(index: LAYER_Z_INDEX): cc.Node {
    if (!this._pushLayerParentDict[index]) {
      this._pushLayerParentDict[index] = new cc.Node();
      this.getCurrScene().addChild(this._pushLayerParentDict[index], index);
      this._pushLayerParentDict[index].x = cc.winSize.width / 2;
      this._pushLayerParentDict[index].y = cc.winSize.height / 2;
    } else if (!this._pushLayerParentDict[index].parent) {
      this.getCurrScene().addChild(this._pushLayerParentDict[index], index);
    }

    return this._pushLayerParentDict[index];
  }

  /**
   * 根据 layerName 获取弹出层
   * @param layerName 
   */
  public getLayer(layerName: any): BaseGameLayer {
    let layer = null;
    for (let i = 0; i < this._pushLayerDict.length; ++i) {
      if (this._pushLayerDict[i].getLayerName() == layerName) {
        layer = this._pushLayerDict[i];
        break;
      }
    }
    return layer;
  }

  /**
   * 清空 所有
   * @param clearPushLayer 
   */
  public removeAllLayer(clearPushLayer: boolean = false): void {
    let layer: BaseGameLayer = null;
    for (let i = this._pushLayerDict.length - 1; i >= 0; --i) {
      layer = this._pushLayerDict[i];
      if (layer && layer.getDisplayView()) {
        if (layer.isReleaseResOnRemoveLayer) {
          layer.DestroyLayerRes();
          this._pushLayerDict.splice(i, 1);
          this._preloadLayer.set(layer.getLayerName(), false);
        }
        if (layer.getDisplayView().parent) {
          layer.getDisplayView().parent.removeChild(layer.getDisplayView());
        }
      }
    }

    for (let k in this._pushLayerParentDict) {
      let parentNode: cc.Node = this._pushLayerParentDict[k];
      if (parentNode && parentNode.parent) {
        parentNode.removeFromParent(false);
      } else {
        this._pushLayerParentDict[k] = null
      }
    }

    // if (clearPushLayer) {
    //   this._pushLayerParentDict = {}
    //   this._pushLayerDict.length = 0;
    // }
  }

  /**
   * 预加载 场景
   * @param sceneName  场景名
   * @param callbackFunc  加载完成回调
   */
  public preLoadScene(sceneName: string, callbackFunc: (error: Error) => void = null): void {
    cc.director.preloadScene(sceneName, null, callbackFunc);
  }

  /**
   * 获取当前场景
   */
  public getCurrScene(): any {
    return cc.director.getScene();
  }

  /**
   * 该层级是否打开
   * @param layerName 
   * @returns 
   */
  public isLayerOpen(layerName): boolean {
    let layer = this.getLayer(layerName);
    // console.log(layer);
    return Boolean(layer.getDisplayView().parent);
  }

  /**
   * 打开 弹出层 动画
   * @param layer 
   * @param layerUnit 
   */
  private actionPushLayer(layer: cc.Node, layerUnit: BaseGameLayer): void {
    let rootNode: cc.Node = layer.getChildByName('rootNode');
    let that: SceneManager = this;

    if (rootNode) {
      rootNode.opacity = 0;
      rootNode.scale = 0.5;

      cc.tween(rootNode)
        .to(0.3, { scale: 1.05, opacity: 255 }, { easing: "backOut" })
        .to(0.05, { scale: 1 }, { easing: "backOut" })
        .call(() => {
          layerUnit.onAddToStage();
          if (that._swallowLayer && that._swallowLayer.node) {
            that._swallowLayer.node.removeFromParent()
          }
        })
        .start();
    } else {
      layerUnit.onAddToStage();
      if (that._swallowLayer && that._swallowLayer.node) {
        cc.tween(that._swallowLayer.node)
          .delay(0.2)
          .call(function () {
            that._swallowLayer.node.removeFromParent()
          })
          .start();
      }
    }
  }

  /**
   * 关闭 弹出层 动画
   * @param layer 
   * @param callbackFunc 
   */
  private actionRemoveLayer(layer: BaseGameLayer, callbackFunc: Function): void {
    let rootNode: cc.Node = layer.getDisplayView().getChildByName('rootNode');
    if (rootNode) {
      cc.tween(rootNode)
        .to(0.15, { scaleX: 2, scaleY: 0 }, { easing: "sineInOut" })
        // .to(0.12, { scale: 0 }, { easing: "sineInOut" })
        .call(() => {
          callbackFunc();
        }, this)
        .start();
    } else {
      callbackFunc();
    }
  }

  /**
   * 释放 资源
   * @param layer 
   */
  private releaseLayer(layer: BaseGameLayer): void {
    if (!layer) {
      return;
    }

    if (!this._pushLayerDict) {
      return;
    }

    layer.DestroyLayerRes();
    this._preloadLayer.set(layer.getLayerName(), false);
    this._pushLayerDict.splice(this._pushLayerDict.indexOf(layer), 1);
  }
}